﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PasteLoggerBoard.redismodel;
using PasteLoggerBoard.reportmodels;
using PasteLoggerBoard.serilogmodels;
using Volo.Abp.Application.Dtos;
using Volo.Abp.DependencyInjection;

namespace PasteLoggerBoard.HttpApi.Host.handler
{
    /// <summary>
    /// 
    /// </summary>
    public class CollectHandler : ISingletonDependency
    {
        /// <summary>
        /// 
        /// </summary>
        public CollectHandler() { }

        #region 写入模块

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">null表示不写入，非null表示使用这个入库</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <param name="_appCache"></param>
        /// <returns>需要null判断</returns>
        public async Task<List<LevelHourReport>> CollectLevelHour(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date, IAppCache _appCache)
        {
            var key = _current_date.ToString("yyyyMMdd");
            var _cachekey = $"{PublicString.CollectLevel}{key}";
            var all_datas = await _appCache.HashGetAllAsync(_cachekey);
            if (all_datas != null && all_datas.Count() > 0)
            {
                var removekeys = new List<string>();
                var add_datas = new List<LevelHourReport>();
                var apps = new List<string>();
                foreach (var item in all_datas)
                {
                    var field = item.Name.ToString();
                    if (!String.IsNullOrEmpty(field))
                    {
                        if (field.Contains("_"))
                        {
                            var strs = field.Split('_');
                            if (strs.Length >= 3)
                            {
                                item.Value.TryParse(out int _value);
                                var _app = strs[0];
                                if (int.TryParse(strs[1], out int _hour))
                                {
                                    if (_hour <= _current_date.Hour)
                                    {
                                        var level = strs[2];
                                        var one = new LevelHourReport
                                        {
                                            AppName = _app,
                                            DataDate = DateTime.Parse(_current_date.ToString($"yyyy-MM-dd {strs[1]}:00:00")),
                                            DataTime = 0,
                                            HitTime = _value,
                                            LogLevel = level
                                        };
                                        add_datas.Add(one);
                                        removekeys.Add(field);
                                    }
                                }
                                if (!apps.Contains(_app))
                                {
                                    apps.Add(_app);
                                }
                            }
                        }
                    }
                }
                if (_dbContext != null)
                {
                    if (add_datas.Count > 0)
                    {
                        _dbContext.AddRange(add_datas);
                        await _dbContext.SaveChangesAsync();
                    }
                    if (apps.Count > 0)
                    {
                        var _apps = _dbContext.AppInfo.Where(x => apps.Contains(x.AppName)).Select(x => x.AppName).ToArray();
                        if (_apps != null && _apps.Length > 0)
                        {
                            foreach (var app in _apps)
                            {
                                apps.Remove(app);
                            }
                        }
                        if (apps.Count > 0)
                        {
                            foreach (var app in apps)
                            {
                                _dbContext.Add(new AppInfo { AppName = app, DisplayName = app });
                            }
                            _dbContext.SaveChanges();
                        }
                    }
                    if (removekeys.Count > 0)
                    {
                        foreach (var item in removekeys)
                        {
                            _appCache.HashDelete(_cachekey, item);
                        }
                    }
                }
                return add_datas;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">必填</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <returns></returns>
        public async Task CollectLevelDay(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date)
        {
            var _start = DateTime.Parse(_current_date.ToString("yyyy-MM-dd 00:00:00"));
            var _end = DateTime.Parse(_current_date.AddDays(1).ToString("yyyy-MM-dd 00:00:00"));

            var datas = await _dbContext.LevelHourReport.Where(x => _start <= x.DataDate && x.DataDate < _end)
                .GroupBy(x => new { app = x.AppName, level = x.LogLevel })
                .Select(x => new LevelDayReport
                {
                    AppName = x.Key.app,
                    DataDate = _start,
                    HitTime = x.Sum(y => y.HitTime),
                    LogLevel = x.Key.level
                })
                .AsNoTracking()
                .ToListAsync();

            if (datas != null && datas.Count > 0)
            {
                _dbContext.AddRange(datas);
                await _dbContext.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">null表示不写入，非null表示使用这个入库</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <param name="_appCache"></param>
        /// <returns>需要null判断</returns>
        public async Task<List<StatusHourReport>> CollectStatusHour(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date, IAppCache _appCache)
        {
            var key = _current_date.ToString("yyyyMMdd");
            var _cachekey = $"{PublicString.CollectStatus}{key}";
            var all_datas = await _appCache.HashGetAllAsync(_cachekey);
            if (all_datas != null && all_datas.Count() > 0)
            {
                var removekeys = new List<string>();
                var add_datas = new List<StatusHourReport>();
                foreach (var item in all_datas)
                {
                    var field = item.Name.ToString();
                    if (!String.IsNullOrEmpty(field))
                    {
                        if (field.Contains("_"))
                        {
                            var strs = field.Split('_');
                            if (strs.Length >= 3)
                            {
                                item.Value.TryParse(out int _value);
                                var _app = strs[0];
                                if (int.TryParse(strs[1], out int _hour))
                                {
                                    if (_hour <= _current_date.Hour)
                                    {
                                        int.TryParse(strs[2], out var _status);
                                        var one = new StatusHourReport
                                        {
                                            AppName = _app,
                                            DataDate = DateTime.Parse(_current_date.ToString($"yyyy-MM-dd {strs[1]}:00:00")),
                                            DataTime = 0,
                                            HitTime = _value,
                                            StatusCode = _status
                                        };
                                        add_datas.Add(one);
                                        removekeys.Add(field);
                                    }
                                }
                            }
                        }
                    }
                }
                if (_dbContext != null)
                {
                    if (add_datas.Count > 0)
                    {
                        _dbContext.AddRange(add_datas);
                        await _dbContext.SaveChangesAsync();
                    }
                    if (removekeys.Count > 0)
                    {
                        foreach (var item in removekeys)
                        {
                            _appCache.HashDelete(_cachekey, item);
                        }
                    }
                }
                return add_datas;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">必填</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <returns></returns>
        public async Task CollectStatusDay(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date)
        {
            var _start = DateTime.Parse(_current_date.ToString("yyyy-MM-dd 00:00:00"));
            var _end = DateTime.Parse(_current_date.AddDays(1).ToString("yyyy-MM-dd 00:00:00"));

            var datas = await _dbContext.StatusHourReport.Where(x => _start <= x.DataDate && x.DataDate < _end)
                .GroupBy(x => new { app = x.AppName, status = x.StatusCode })
                .Select(x => new StatusDayReport
                {
                    AppName = x.Key.app,
                    DataDate = _start,
                    HitTime = x.Sum(y => y.HitTime),
                    StatusCode = x.Key.status
                })
                .AsNoTracking()
                .ToListAsync();

            if (datas != null && datas.Count > 0)
            {
                _dbContext.AddRange(datas);
                await _dbContext.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">null表示不写入，非null表示使用这个入库</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <param name="_appCache"></param>
        /// <returns>需要null判断</returns>
        public async Task<List<PathHourReport>> CollectPathHour(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date, IAppCache _appCache)
        {
            var key = _current_date.ToString("yyyyMMdd");
            var _cachekey = $"{PublicString.CollectPath}{key}";
            var all_datas = await _appCache.HashGetAllAsync(_cachekey);
            if (all_datas != null && all_datas.Count() > 0)
            {
                var removekeys = new List<string>();
                var add_datas = new List<PathHourReport>();
                foreach (var item in all_datas)
                {
                    var field = item.Name.ToString();
                    if (!String.IsNullOrEmpty(field))
                    {
                        if (field.Contains("_"))
                        {
                            var strs = field.Split('_');
                            if (strs.Length >= 3)
                            {
                                item.Value.TryParse(out int _value);
                                var _app = strs[0];
                                if (int.TryParse(strs[1], out int _hour))
                                {
                                    if (_hour <= _current_date.Hour)
                                    {
                                        var level = strs[2];
                                        var one = new PathHourReport
                                        {
                                            AppName = _app,
                                            DataDate = DateTime.Parse(_current_date.ToString($"yyyy-MM-dd {strs[1]}:00:00")),
                                            DataTime = 0,
                                            HitTime = _value,
                                            Path = level
                                        };
                                        add_datas.Add(one);
                                        removekeys.Add(field);
                                    }
                                }
                            }
                        }
                    }
                }
                if (_dbContext != null)
                {
                    if (add_datas.Count > 0)
                    {
                        _dbContext.AddRange(add_datas);
                        await _dbContext.SaveChangesAsync();
                    }
                    if (removekeys.Count > 0)
                    {
                        foreach (var item in removekeys)
                        {
                            _appCache.HashDelete(_cachekey, item);
                        }
                    }
                }
                return add_datas;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext">必填</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <returns></returns>
        public async Task CollectPathDay(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date)
        {
            var _start = DateTime.Parse(_current_date.ToString("yyyy-MM-dd 00:00:00"));
            var _end = DateTime.Parse(_current_date.AddDays(1).ToString("yyyy-MM-dd 00:00:00"));

            var datas = await _dbContext.PathHourReport.Where(x => _start <= x.DataDate && x.DataDate < _end)
                .GroupBy(x => new { app = x.AppName, path = x.Path })
                .Select(x => new PathDayReport
                {
                    AppName = x.Key.app,
                    DataDate = _start,
                    HitTime = x.Sum(y => y.HitTime),
                    Path = x.Key.path
                })
                .AsNoTracking()
                .ToListAsync();

            if (datas != null && datas.Count > 0)
            {
                _dbContext.AddRange(datas);
                await _dbContext.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 立马按照分页的模式获取ip信息
        /// 返回数据只会返回第一页的数据
        /// IP模式中没有天数据
        /// </summary>
        /// <param name="_dbContext">必填</param>
        /// <param name="_current_date">数据当前时间</param>
        /// <param name="_appCache"></param>
        /// <returns>只返回第一页的</returns>
        public async Task CollectClientIpHour(IPasteLoggerBoardDbContext _dbContext, DateTime _current_date, IAppCache _appCache)
        {
            var key = _current_date.ToString("yyyyMMdd");
            var _cachekey = $"{PublicString.CollectClientIp}{key}";
            var _next = true;//只读取前1000条数据 先做测试用
            var _page = 1;
            var _size = 1000;
            //var returndatas = new List<ClientIpHourReport>();//只返回第一页的
            var removekeys = new List<string>();
            while (_next)
            {
                var all_datas = await _appCache.HashScanAsync(_cachekey, "*", _page, _size);
                if (all_datas != null && all_datas.Count > 0)
                {
                    var add_datas = new List<ClientIpHourReport>();
                    foreach (var item in all_datas)
                    {
                        var field = item.Name.ToString();
                        if (!String.IsNullOrEmpty(field))
                        {
                            if (field.Contains("_"))
                            {
                                var strs = field.Split('_');
                                if (strs.Length >= 3)
                                {
                                    item.Value.TryParse(out int _value);
                                    var _app = strs[0];
                                    if (int.TryParse(strs[1], out int _hour))
                                    {
                                        if (_hour <= _current_date.Hour)
                                        {
                                            var level = strs[2];
                                            var one = new ClientIpHourReport
                                            {
                                                AppName = _app,
                                                DataDate = DateTime.Parse(_current_date.ToString($"yyyy-MM-dd {strs[1]}:00:00")),
                                                HitTime = _value,
                                                ClientIp = level
                                            };
                                            add_datas.Add(one);
                                            removekeys.Add(field);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (add_datas.Count > 0)
                    {
                        _dbContext.AddRange(add_datas);
                        await _dbContext.SaveChangesAsync();
                    }
                    //if (_page == 1)
                    //{
                    //    returndatas.AddRange(add_datas);
                    //}
                    if (all_datas.Count != _size)
                    {
                        _next = false;
                    }
                }
                else
                {
                    _next = false;
                    Console.WriteLine($"{DateTime.Now}没有从{_cachekey}获取到数据！");
                }
                _page++;
                if (_page > 2)
                {
                    _next = false;
                }
            }
            if (removekeys.Count > 0)
            {
                foreach (var item in removekeys)
                {
                    _appCache.HashDelete(_cachekey, item);
                }
                Console.WriteLine($"{DateTime.Now}写入日志信息{removekeys.Count}条!");
            }
        }

        #endregion

        #region 读取报表模块

        /// <summary>
        /// 读取各等级的报表信息
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <returns></returns>
        public async Task<List<ReportLevel>> ReportLevel(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname)
        {
            if (edate.Subtract(sdate).TotalDays >= 2)
            {
                var datas = await _dbContext.LevelDayReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.LogLevel, vdate = x.DataDate })
                    .Select(x => new ReportLevel
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        LogLevel = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
            else
            {
                var datas = await _dbContext.LevelHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.LogLevel, vdate = x.DataDate })
                    .Select(x => new ReportLevel
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        LogLevel = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
        }

        /// <summary>
        /// 读取状态码的报表信息
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <returns></returns>
        public async Task<List<ReportStatus>> ReportStatus(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname)
        {
            if (edate.Subtract(sdate).TotalDays >= 2)
            {
                var datas = await _dbContext.StatusDayReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.StatusCode, vdate = x.DataDate })
                    .Select(x => new ReportStatus
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        StatusCode = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
            else
            {
                var datas = await _dbContext.StatusHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.StatusCode, vdate = x.DataDate })
                    .Select(x => new ReportStatus
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        StatusCode = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
        }

        /// <summary>
        /// 读取状态码的报表信息
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <returns></returns>
        public async Task<List<ReportPath>> ReportPath(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname)
        {
            if (edate.Subtract(sdate).TotalDays >= 2)
            {
                var datas = await _dbContext.PathDayReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.Path, vdate = x.DataDate })
                    .Select(x => new ReportPath
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        Path = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
            else
            {
                var datas = await _dbContext.PathHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                    .GroupBy(x => new { level = x.Path, vdate = x.DataDate })
                    .Select(x => new ReportPath
                    {
                        DataDate = x.Key.vdate,
                        HitTime = x.Sum(y => y.HitTime),
                        Path = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .AsNoTracking()
                    .ToListAsync();
                return datas;
            }
        }

        /// <summary>
        /// 按照访问次数倒叙
        /// 按照分页查询
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ReportPath>> ReportSumPath(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname, int page = 1, int size = 100)
        {
            var _pagedto = new PagedResultDto<ReportPath>();
            if (edate.Subtract(sdate).TotalDays >= 2)
            {
                var _query = _dbContext.PathDayReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname);
                var datas = await _query
                    .GroupBy(x => new { level = x.Path })
                    .Select(x => new ReportPath
                    {
                        DataDate = sdate,
                        HitTime = x.Sum(y => y.HitTime),
                        Path = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .Page(page, size)
                    .AsNoTracking()
                    .ToListAsync();
                if (datas.Count > 0)
                {
                    _pagedto.Items = datas;
                    if (page == 1)
                    {
                        _pagedto.TotalCount = await _query.GroupBy(x => x.Path).CountAsync();
                    }
                }
            }
            else
            {
                var _query = _dbContext.PathHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname);
                var datas = await _query
                    .GroupBy(x => new { level = x.Path })
                    .Select(x => new ReportPath
                    {
                        DataDate = sdate,
                        HitTime = x.Sum(y => y.HitTime),
                        Path = x.Key.level
                    })
                    .OrderByDescending(x => x.HitTime)
                    .Page(page, size)
                    .AsNoTracking()
                    .ToListAsync();
                if (datas.Count > 0)
                {
                    _pagedto.Items = datas;
                    if (page == 1)
                    {
                        _pagedto.TotalCount = await _query.GroupBy(x => x.Path).CountAsync();
                    }
                }
            }
            return _pagedto;
        }

        /// <summary>
        /// 读取IP访问信息
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public async Task<List<ReportClientIp>> ReportClientIp(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname, int page = 1, int size = 100)
        {
            var datas = await _dbContext.ClientIpHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname)
                .GroupBy(x => new { level = x.ClientIp, vdate = x.DataDate })
                .Select(x => new ReportClientIp
                {
                    DataDate = x.Key.vdate,
                    HitTime = x.Sum(y => y.HitTime),
                    ClientIp = x.Key.level
                })
                .OrderByDescending(x => x.HitTime)
                .AsNoTracking()
                .Page(page, size)
                .ToListAsync();
            return datas;
        }

        /// <summary>
        /// 按照访问次数倒叙
        /// 按照分页查询
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="sdate"></param>
        /// <param name="edate"></param>
        /// <param name="appname"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ReportClientIp>> ReportSumClientIp(IPasteLoggerBoardDbContext _dbContext, DateTime sdate, DateTime edate, string appname, int page = 1, int size = 100)
        {
            var _pagedto = new PagedResultDto<ReportClientIp>();
            var _query = _dbContext.ClientIpHourReport.Where(x => sdate <= x.DataDate && x.DataDate < edate && x.AppName == appname);
            var datas = await _query
                .GroupBy(x => new { level = x.ClientIp })
                .Select(x => new ReportClientIp
                {
                    DataDate = sdate,
                    HitTime = x.Sum(y => y.HitTime),
                    ClientIp = x.Key.level
                })
                .OrderByDescending(x => x.HitTime)
                .AsNoTracking()
                .Page(page, size)
                .ToListAsync();
            if (datas.Count > 0)
            {
                _pagedto.Items = datas;
                if (page == 1)
                {
                    _pagedto.TotalCount = await _query.GroupBy(x => x.ClientIp).CountAsync();
                }
            }
            return _pagedto;
        }

        #endregion

    }
}
